package lex.expression;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Stack;

import lex.expression.tree.ExpressionTree;
import lex.expression.tree.Node;



public class Usage implements Runnable
{
	public static void main( String[] args )
	{
		new Usage().run();
	}

	private Lexer lexer = null;
	private Parser parser = null;
	private Calculator caltulator = null;
	private ExpressionTree treeParser = null;

	public void run()
	{
		boolean exit = false;
		while( false == exit )
		{
			ln( "Type in expression: " );
			String expression = this.readLine();
			this.maybeExitCommand( expression );
			ln( "Tokens: " );
			this.lexerTest( expression );
			ln( "\nPostfix: " );
			this.parserTest( expression );
			ln( "\nTree: " );
			this.treeTest( expression );
//			System.out.print( "\nResult: " );
//			this.calculatorTest( expression );
		}
	}

	void lexerTest( String expr )
	{
		this.getLexer().setSource( expr );
		while( true )
		{
			Token token = this.lexer.nextToken();
			if( token.getTokenType() == TokenType.END )
				return;
			ln( token.toString() );
		}
	}

	void parserTest( String expression )
	{
		PostfixExpression postfix = this.getParser().parse( expression );
		ln( this.toString( postfix.getPostfix() ) );
	}
	
	void treeTest( String expression )
	{
		PostfixExpression postfix = this.getParser().parse( expression );
		Node node = this.getTreeParser().parseRootNode( postfix );
		node.print( System.out, 2 );
	}

	void calculatorTest( String expression )
	{
		PostfixExpression postfix = this.getParser().parse( expression );
		Number result = this.getCaltulator().calculate( postfix );
		ln( result + "\n" );
	}

	private Lexer getLexer()
	{
		if( null == this.lexer )
			this.lexer = new Lexer();
		return lexer;
	}

	private Parser getParser()
	{
		if( null == parser )
			this.parser = new Parser();
		return parser;
	}

	private ExpressionTree getTreeParser()
	{
		if( null == treeParser )
			this.treeParser = new ExpressionTree();
		return treeParser;
	}

	private Calculator getCaltulator()
	{
		if( null == this.caltulator )
			this.caltulator = new Calculator();
		return caltulator;
	}

	private void maybeExitCommand( String input )
	{
		if( input.startsWith( "exit" ) || input.startsWith( "quit" ) )
		{
			ln( "\nBye~" );
			System.exit( 0 );
		}
	}

	private BufferedReader reader = new BufferedReader( new InputStreamReader( System.in ) );

	private String readLine()
	{
		try
		{
			return reader.readLine();
		}
		catch( IOException e )
		{
			return this.getDefaultExpression();
		}
	}

	private String getDefaultExpression()
	{
		// 1 202 31 3 - * 5 / +
		return "1  + 202 * ( 31 - 3 ) / (5)";
	}

	private void ln( String s )
	{
		System.out.println( s );
	}

	private String toString( Stack<?> stack )
	{
		StringBuilder buffer = new StringBuilder();
		while( false == stack.empty() )
			buffer.append( stack.pop() ).append( ' ' );
		return buffer.toString();
	}
}
